﻿using Furion.DependencyInjection;
using Furion.Extras.Admin.NET.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Furion.DependencyInjection;
using Furion.RemoteRequest.Extensions;
using Microsoft.Extensions.Configuration;
using Furion.FriendlyException;
using Furion.Extras.Admin.NET;
using Furion;

namespace Admin.NET.Core.Weapp
{
    /// <summary>
    /// 微信身份验证功能
    /// </summary>
    public class WeappApi : ISingleton, IWeappApi
    {
        public static string GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

        public static readonly string CODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";

        public async Task<Code2SessionModel> Code2SessionAsync(string code, string grant_type = "authorization_code")
        {
            var param = new Dictionary<string, string>()
            {
                ["appid"] = App.Configuration["OAuth:Weapp:app_id"],
                ["secret"] = App.Configuration["OAuth:Weapp:AppSecret"],
                ["grant_type"] = grant_type ,
                ["js_code"] = code,
            };
            var userInfoModel = await $"{CODE2SESSION_URL}?{param.ToQueryString()}".GetAsAsync<Code2SessionModel>();
            return userInfoModel;
        }

        public WeappTokenModel CurrentToken { get; private set; }
        private DateTime? _TokenTime;

        private bool _refereshing = false;

        public async Task<WeappTokenModel> GetAccessTokenAsync()
        {
            while (this._refereshing)
            {
                await Task.Delay(100);
            }
            this._refereshing = true;
            try
            {
                if (this.CurrentToken == null ||
                    // 凭证时效小于120秒时，需要刷新token
                    (DateTime.Now -
                    this._TokenTime.Value.AddSeconds(this.CurrentToken.ExpiresIn)).TotalSeconds <= 120)
                {
                    this.CurrentToken = await this._GetAccessToken();
                    _TokenTime = DateTime.Now;
                }
                return this.CurrentToken;
            }
            finally
            {
                this._refereshing = false;
            }
        }

        private async Task<WeappTokenModel> _GetAccessToken(string grant_type = "client_credential")
        {
            var param = new Dictionary<string, string>()
            {
                ["appid"] = App.Configuration["OAuth.Weapp.AppId"],
                ["secret"] = App.Configuration["OAuth.Weapp.AppSecret"],
                ["grant_type"] = grant_type
            };
            return await $"{GET_ACCESS_TOKEN_URL}?{param.ToQueryString()}".GetAsAsync<WeappTokenModel>();
        }
    }
}